/*
 * @Author: Suo-Yuheng syh15399227325@163.com
 * @Date: 2025-09-23 17:16:01
 * @LastEditors: Suo-Yuheng syh15399227325@163.com
 * @LastEditTime: 2025-09-23 21:19:13
 * @FilePath: /0923/Reactor/TcpServer.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <functional>
#include <unordered_map>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <cstring>
#include "log.hpp"
#include "nocopy.hpp"
#include "Epoller.hpp"
#include "Socket.hpp"
#include "Comm.hpp"

uint32_t EVENT_IN = (EPOLLIN | EPOLLET); // ET 模式工作
uint32_t EVENT_OUT = (EPOLLOUT | EPOLLET);
static const int g_buffer_size = 128;

class Connection;
class TcpServer;

using func_t = std::function<void(std::shared_ptr<Connection>)>; // 返回 connection 对象
using except_func = std::function<void(std::weak_ptr<Connection>)>;

class Connection
{
public:
    Connection(int sock, std::weak_ptr<TcpServer> tcp_server_ptr)
        : _sock(sock), _tcp_server_ptr(tcp_server_ptr)
    {
    }

    void SetHandler(func_t recv_cb, func_t send_cb, except_func except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }

    int Sockfd()
    {
        return _sock;
    }

    void AppendInbuffer(const std::string &info)
    {
        _inbuffer += info;
    }
    void AppendOutbuffer(const std::string &info)
    {
        _outbuffer += info;
    }

    const std::string &inbuffer()
    {
        return _inbuffer;
    }
    const std::string &outbuffer()
    {
        return _outbuffer;
    }
    

    ~Connection()
    {
    }

private:
    int _sock;
    std::string _inbuffer; // 处理二进制流的话 vector 更合适
    std::string _outbuffer;

public:
    func_t _recv_cb;
    func_t _send_cb;
    except_func _except_cb;

    // 添加一个回指指针
    std::shared_ptr<TcpServer> _tcp_server_ptr;
    // std::weak_ptr<TcpServer> _tcp_server_ptr; // bug？

    std::string _ip;
    uint16_t _port;
};

class TcpServer : public nocopy
{
    static const int num = 64;

public:
    TcpServer(uint16_t port, func_t OnMessage)
        : _port(port), _epoller_ptr(new Epoller()), _listensock_ptr(new Sock()), _quit(true), _OnMessage(OnMessage)
    {
    }

    void Init()
    {
        _listensock_ptr->Socket();
        SetNonBlockOrDie(_listensock_ptr->Fd()); // 设置fd 为非阻塞，因为要以 ET 模式运行
        _listensock_ptr->Bind(_port);
        _listensock_ptr->Listen();
        lg(Info, "create listen socket success: %d\n", _listensock_ptr->Fd());

        AddConnection(_listensock_ptr->Fd(), EVENT_IN,
                      std::bind(&TcpServer::Accepter, this, std::placeholders::_1),
                      nullptr,
                      nullptr,
                      "0.0.0.0", 8585); // 添加进 connecton 中管理
    }

    void AddConnection(int sock, uint32_t event, func_t recv_cb, func_t send_cb, except_func except_cb, const std::string &ip = "0.0.0.0",
                       const uint16_t port = 8585)
    {
        // 1、给 sock 建立一个 connection对象，将 listensock添加到connection中，同时，listensock和connection 放进map中
        std::shared_ptr<Connection> new_connection = std::make_shared<Connection>(sock, std::shared_ptr<TcpServer>(this));
        new_connection->SetHandler(recv_cb, send_cb, except_cb);
        new_connection->_ip = ip;
        new_connection->_port = port;

        // 2、 添加到 unordered map 中，进行管理
        _connections.insert(std::make_pair(sock, new_connection));

        // 3、将 sock 添加到 epoll 中：就是把 listensock 和它关心的事件，添加到内核 epoll 模型中，rb_tree 节点
        _epoller_ptr->EpollerUpdate(EPOLL_CTL_ADD, sock, event);

        lg(Debug, "add a new connection success, sockfd is: %d", sock);
    }

    // 连接管理器
    void Accepter(std::shared_ptr<Connection> connection)
    {
        while (true)
        {
            // 获取新连接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sock = ::accept(connection->Sockfd(), reinterpret_cast<struct sockaddr *>(&peer), &len);
            if (sock > 0)
            {
                uint16_t peerport = ntohs(peer.sin_port);
                char ipbuf[128];
                inet_ntop(AF_INET, &peer.sin_addr.s_addr, ipbuf, sizeof(ipbuf));
                std::string peerip = ipbuf;
                lg(Debug, "get a new client, get info-> [%s:%d], sockfd: %d", peerip.c_str(), peerport, sock);

                SetNonBlockOrDie(sock); // 设置fd 为非阻塞，因为要以 ET 模式运行
                AddConnection(sock, EVENT_IN,
                              std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                              std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                              std::bind(&TcpServer::Excepter, this, std::placeholders::_1),
                              peerip, peerport); // 将这个新连接 添加到 map中管理，再 添加到 epoll 模型中，监听，TODO
            }
            else
            {
                if (errno == EWOULDBLOCK)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                    break;
            }
        }
    }

    // 事件管理器
    void Recver(std::shared_ptr<Connection> connection)
    {
        int sock = connection->Sockfd();
        while (true) // ET 模式下，需要一直读完
        {
            char buffer[g_buffer_size];
            memset(buffer, '\0', sizeof(buffer));
            ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0); // 虽然参数为0 表示阻塞读取，但之前已经设置fd 非阻塞了，所以非阻塞读取
            if (n > 0)                                             // 读取成功，接着读，直到出错
            {
                connection->AppendInbuffer(buffer);
            }
            else if (n == 0) // 对端 关闭连接
            {
                lg(Info, "sockfd: %d, client info %s:%d quit...", sock, connection->_ip.c_str(), connection->_port);
                connection->_except_cb(connection);
            }
            else // 读取出错，检查出错吗
            {
                if (errno == EWOULDBLOCK)
                    break; // 读完了
                else if (errno == EINTR)
                    continue; // 被信号中断
                else
                {
                    lg(Info, "sockfd: %d, client info %s:%d recv error...", sock, connection->_ip.c_str(), connection->_port);
                    connection->_except_cb(connection);
                    return;
                }
            }
        }

        // 此时，上层需要：1、检测数据是否完整   2、如果有完整报文，就处理
        // 那么就需要 上层根据 特定协议 进行解包，反序列化，处理数据，然后构建响应...
        _OnMessage(connection); // 读完了，交给上层处理，读到的数据都在 connection 中
        
    }

    void Sender(std::shared_ptr<Connection> connection)
    {
        std::string outbuffer = connection->outbuffer();
        while(true) // ET 模式
        {
            ssize_t n = send(connection->Sockfd(), outbuffer.c_str(), outbuffer.size(), 0);
            if(n > 0)
            {
                outbuffer.erase(0, n);
                if(outbuffer.empty())
                    break;
            }
            else if(n == 0)
            {
                return;
            }
            else
            {
                // 出错了
                if(errno == EWOULDBLOCK)    // 底层接收缓冲区可能没空间了
                    break;
                else if(errno == EINTR)
                    continue;
                else
                {
                    lg(Info, "sockfd: %d, client info %s:%d send error...", connection->Sockfd(), connection->_ip.c_str(), connection->_port);
                    connection->_except_cb(connection);
                    return;
                }
            }
        }
        if(!outbuffer.empty())
        {
            // 本轮没发完，需要开启对 写事件的 关心，等fd 有空间了，再去写
            EnableEvent(connection->Sockfd(), true, true);
        }
        else
        {
            // 发完了，需要关闭对 写事件 的关心
            EnableEvent(connection->Sockfd(), true, false);
        }
    }

    void Excepter(std::weak_ptr<Connection> connection)
    {
        if(connection.expired()) return;
        auto conn = connection.lock();
        
        lg(Warning, "Excepter hander sockfd: %d, client info %s:%d excepter handler", conn->Sockfd(), conn->_ip.c_str(), conn->_port);
        

        // 1、移除对特定 fd 的关心
        // EnableEvent(connection->Sockfd(), false, false);
        _epoller_ptr->EpollerUpdate(EPOLL_CTL_DEL, conn->Sockfd(), 0);

        // 2、关闭异常 fd
        lg(Debug, "close %d done...\n", conn->Sockfd());
        close(conn->Sockfd());

        // 3、从 unordered map 中移除该连接
        _connections.erase(conn->Sockfd());
        // _connections[conn->Sockfd()].reset();
        lg(Debug, "remove %d from _connections...\n", conn->Sockfd());
    }

    void EnableEvent(int sock, bool readable, bool writeable)
    {
        uint32_t events = 0;
        events |= ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET);
        _epoller_ptr->EpollerUpdate(EPOLL_CTL_MOD, sock, events);
    }

    bool IsConnectionSafe(int fd)
    {
        auto iter = _connections.find(fd);
        if (iter == _connections.end())
            return false;
        else
            return true;
    }

    void Dispatcher(int timeout)
    {
        int n = _epoller_ptr->EpollerWait(revs, num, timeout); // 从底层捞 已经就绪的事件、从 epoll 的就绪队列里捞
        for (int i = 0; i < n; i++)                            // 事件就绪：可能是超时、异常、成功
        {
            uint32_t events = revs[i].events;
            int sock = revs[i].data.fd;

            // 统一 把事件异常，转换为  读写问题
            if (events & EPOLLERR) // 出错
                events |= (EPOLLIN | EPOLLOUT);
            if (events & EPOLLHUP) // 对方把连接关了
                events |= (EPOLLIN | EPOLLOUT);

            // 只需要处理 读写
            if ((events & EPOLLIN) && IsConnectionSafe(sock))
            {
                if (_connections[sock]->_recv_cb) // 判断读回调是否设置
                    _connections[sock]->_recv_cb(_connections[sock]);
            }
            if ((events & EPOLLOUT) && IsConnectionSafe(sock))
            {
                if (_connections[sock]->_send_cb) // 判断写回调是否设置
                    _connections[sock]->_send_cb(_connections[sock]);
            }
        }
    }

    void Loop()
    {
        _quit = false;

        // AddConnection();
        while (!_quit) // 事件派发
        {
            Dispatcher(-1);
            // Dispatcher(3000);
            PrintConnection();
        }

        _quit = true;
    }

    void PrintConnection()
    {
        std::cout << "_connections fd list: ";
        for (auto &connection : _connections)
        {
            std::cout << connection.second->Sockfd() << ", ";
            std::cout << connection.second->inbuffer();
        }
        std::cout << std::endl;
    }

    ~TcpServer()
    {
    }

private:
    std::shared_ptr<Epoller> _epoller_ptr;                             // 内核中的 epoller 对象
    std::shared_ptr<Sock> _listensock_ptr;                             // 监听套接字
    std::unordered_map<int, std::shared_ptr<Connection>> _connections; // 管理所有连接， (fd，连接指针)
    struct epoll_event revs[num];
    uint16_t _port;
    bool _quit;

    // 让上层处理信息
    func_t _OnMessage;
};